// Ninf-G-XX, ver. 0.1
// Copyright 2011 National Institute of Advanced Industrial Science and Technology
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
 * URI.hpp
 *
 *  Created on: Jan 28, 2009
 *      Author: nakada
 */

#ifndef URI_HPP_
#define URI_HPP_
#include <string>
#include <iostream>
#include <sstream>
#include <boost/regex.hpp>

namespace ninf {
namespace lib {

/**
 *  assumed URI
 *  scheme://[user@][host][:port]/[path][?query][#fragment]
 */
class URI {
public:
  std::string scheme;
  std::string authority;
  std::string user;
  std::string host;
  int         port;
  std::string body;
  std::string path;
  std::string query;
  std::string fragment;
  bool        sane;

  URI(std::string s) {
    static const char * pattern = "\\A([^:]+)://"   // scheme
      "((?:([^:/@]*)@)?([^:@/]*)(?::(\\d+))?)/"   // authority = [user-info@]host[:port]
      "(([^\\?]*)(?:\\?([^#]*))?(?:#(.*))?)\\z";    // body = [path?query#fragment]

    static const boost::regex e(pattern);
    boost::smatch match;
    if (! regex_match(s, match, e)) {
      this->sane = false;
      return;
    }
    this->scheme    = match[1].str();
    this->authority = match[2].str();
    this->user      = match[3].str();
    this->host      = match[4].str();
    this->port      = atoi(match[5].str().c_str());
    this->body      = match[6].str();
    this->path      = match[7].str();
    this->query     = match[8].str();
    this->fragment  = match[9].str();
    this->sane      = true;
  }

  URI(const URI & that) {
    this->scheme    = that.scheme;
    this->authority = that.authority;
    this->user      = that.user;
    this->host      = that.host;
    this->port      = that.port;
    this->body      = that.body;
    this->path      = that.path;
    this->query     = that.query;
    this->fragment  = that.fragment;
    this->sane      = that.sane;
  }

  std::string toString() const {
    return scheme + "://" + authority + "/" + body;
  }
  std::string dump() {
    std::ostringstream os;
    os << "scheme: "    << scheme    << ",\t";
    os << "authority: " << authority << ",\t";
    os << "user: "      << user      << ",\t";
    os << "host: "      << host      << ",\t";
    os << "port: "      << port      << ",\t";
    os << "path: "      << path      << ",\t";
    os << "query: "     << query     << ",\t";
    os << "fragment: "  << fragment;
    return os.str();
  }

  bool operator==(const URI & b){
    return toString() == b.toString();
  }
  bool operator!=(const URI & b){
    return ! (*this == b);
  }

};
  std::ostream& operator<<(std::ostream& os, const ninf::lib::URI & uri);

/**
  bool operator==(URI & a, URI & b){
    return a.toString() == b.toString();
  }
  bool operator!=(URI & a, URI & b){
    return ! (a == b);
  }
*/
}
}

#endif /* URI_HPP_ */
